﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BEPUphysics.Entities;
using Microsoft.Xna.Framework;
using BEPUphysics.MathExtensions;

namespace The_LarX
{
    /// <summary>
    /// Class that holds a bEPU Entity
    /// </summary>
    public abstract class BepuEntity 
    {
        public Actor Actor;
        public Entity Entity;

        public virtual Vector3 Position
        {
            get { return Entity.Position; }
            set { Entity.Position = value; }
        }

        public virtual Vector3 Velocity
        {
            get { return Entity.LinearVelocity; }
            set { Entity.LinearVelocity = value; }
        }

        public virtual Vector3 Scale
        {
            get;
            set;
        }

        private Vector3 rotation;
        public virtual Vector3 Rotation
        {
            get { return rotation; }
            set
            {
                rotation = value;                
                Entity.Orientation = Quaternion.CreateFromYawPitchRoll(value.Y,
                    value.X, value.Z);
            }
        }

        public virtual float Mass
        {
            get { return Entity.Mass; }
            set { Entity.Mass = value; }
        }

        private bool immovable;
        public virtual bool Immovable
        {
            get { return !Entity.IsDynamic; }
            set
            {
                immovable = value;
                if (value)
                {
                    Entity.BecomeKinematic();
                    Entity.LinearVelocity = Vector3.Zero;
                    Entity.AngularVelocity = Vector3.Zero;
                }
                else
                {
                    if (Mass == 0)
                    {
                        Mass = 1;
                    }
                    Entity.BecomeDynamic(Mass);
                }
            }
        }

        public virtual float DirectionVelocity
        {
            get { return 0; }
            set
            {
                Vector3 Direction = Vector3.Forward;
                Direction = Vector3.Transform(Direction, Matrix.CreateFromYawPitchRoll(Rotation.Y,
                    Rotation.X, Rotation.Z));
                Entity.LinearVelocity = Direction * value;
            }
        }

        public string Name { get; set; }

        private static int count;
        public BepuEntity()
        {
            EngineSystem.BepuEntities.Add(this);
            this.Name = "BepuEntity" + count++;
        }

        public virtual void SerializeData(SerializeData Data)
        {
            Data.AddData("BepuEntity.Mass", this.Mass);
            Data.AddData("BepuEntity.Position", this.Position);
            Data.AddData("BepuEntity.Scale", this.Scale);
            Data.AddData("BepuEntity.Immovable", this.Immovable);
            Data.AddData("BepuEntity.Name", this.Name);
            Data.AddData("BepuEntity.Rotation", rotation);
        }
        public virtual void DeserializeData(SerializeData Data)
        {
            this.Mass = Data.GetData<float>("BepuEntity.Mass");
            this.Position = Data.GetData<Vector3>("BepuEntity.Position");
            this.Scale = Data.GetData<Vector3>("BepuEntity.Scale");
            this.Immovable = Data.GetData<bool>("BepuEntity.Immovable");
            this.Name = Data.GetData<string>("BepuEntity.Name");
            if (Immovable)
            {
                this.Rotation = Data.GetData<Vector3>("BepuEntity.Rotation");
            }
        }

        public virtual void SetActor(Actor actor)
        {
            actor.RotationMatrix = Matrix3X3.ToMatrix4X4(this.Entity.OrientationMatrix);
        }

        public virtual void Update()
        {
            if (immovable)
            {
                Entity.BecomeKinematic();
                Entity.LinearVelocity = Vector3.Zero;
                Entity.AngularVelocity = Vector3.Zero;
            }
        }
        public Matrix InfiniteMatrix()
        {
            return new Matrix(float.PositiveInfinity,
                float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
                float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
                float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
                float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
        }
    }
}
